﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using System.Collections;
using System.Text.RegularExpressions;

namespace Light.Utility
{

    /// <summary>
    /// JSON数据转换器
    /// </summary>
    public class JsonConverter
    {

        /// <summary>
        /// 将DataTable转换成JSON数据
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static string DataTableToJson(DataTable dt)
        {

            if (dt == null || dt.Rows.Count == 0) return string.Empty;

            //[{"name":"abc","age":"23"},{"name":"bcd","age":"25"}]
            StringBuilder builder = new StringBuilder();

            builder.Append("[");

            int cntRow = dt.Rows.Count;
            int cntCol = dt.Columns.Count;

            for (int i = 0; i < cntRow; i++)
            {
                builder.Append("{");
                for (int j = 0; j < cntCol; j++)
                {
                    builder.Append("\"" + dt.Columns[j].ColumnName + "\"");
                    builder.Append(":");
                    if (dt.Rows[i][j] != null)
                    {
                        builder.Append("\"" + FormatString(dt.Rows[i][j]) + "\"");
                    }
                    else
                    {
                        builder.Append("\" \"");
                    }
                    builder.Append(",");
                }
                builder.Remove(builder.Length - 1, 1);
                builder.Append("}");
                builder.Append(",");
            }

            builder.Remove(builder.Length - 1, 1);
            builder.Append("]");

            return builder.ToString();

        }


        /// <summary>
        ///  将对象序列化为JSON数据（保留原有string,bool,decimal,double数据类型）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">需要json化的对象实例,json化所有可json化的属性</param>
        /// <returns></returns>
        public static string Serialize<T>(T obj)
        {
            return Serialize<T>(obj, null, false);
        }

        /// <summary>
        /// 将对象序列化为JSON数据（保留原有string,int,bool,decimal,double数据类型）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs">需要json化的对象实例,json化所有可json化的属性</param>
        /// <returns></returns>
        public static string Serialize<T>(IEnumerable<T> objs)
        {
            return Serialize<T>(objs, null);
        }
        /// <summary>
        /// 将对象序列化为JSON数据（保留原有string,bool,decimal,double数据类型）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs">需要json化的对象实例</param>
        /// <param name="properties">需要json化的属性名集合，为null时表示json化所有可json化的属性</param>
        /// <returns></returns>
        public static string Serialize<T>(IEnumerable<T> objs, IList<string> properties)
        {
            return Serialize<T>(objs, properties, false);
        }

        /// <summary>
        /// 将对象转换成JSON数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">需要json化的对象实例</param>
        /// <param name="properties">需要json化的属性名集合，为null时表示json化所有可json化的属性</param>
        /// <param name="valueTypeToString">值类型是否转换为字符串类型</param>
        /// <returns></returns>
        public static string Serialize<T>(T obj, IList<string> properties, bool valueTypeToString)
        {
            if (properties == null || properties.Count == 0)
                properties = ReflectionHelper.GetProperties<T>();

            StringBuilder builder = new StringBuilder();

            builder.Append("{");
            foreach (var property in properties)
            {
                string key = property;

                //忽略不进行JSON序列化的属性
                if (ReflectionHelper.HasAttribute<T, NonJsonSerializeAttribute>(property))
                    continue;
                if (ReflectionHelper.HasAttribute<T, JsonSerializeAttribute>(property))
                {
                    string ignore = ReflectionHelper.GetPropertyAttribute<T, JsonSerializeAttribute>(property, "IgnoreMobile");
                    if (Boolean.Parse(ignore) && WebHelper.IsMobileDevice())
                        continue;
                    string cKey = ReflectionHelper.GetPropertyAttribute<T, JsonSerializeAttribute>(property, "Key");
                    key = !String.IsNullOrEmpty(cKey) ? cKey : key;
                }
                object value = ReflectionHelper.GetPropertyValue(obj, property);


                builder.Append("\"" + key + "\"");
                builder.Append(":");

                if (!valueTypeToString && (value is Int32 || value is Boolean || value is Decimal || value is Double))
                {
                    builder.Append(value.ToString().ToLower());
                }
                else
                {
                    builder.Append("\"" + FormatString(value) + "\"");
                }
                builder.Append(",");

                if (value is Enum)
                {
                    builder.Append("\"" + key + "Value\"");
                    builder.Append(":");
                    builder.Append("\"" + Convert.ToInt32(value) + "\"");
                    builder.Append(",");
                }

            }
            builder.Remove(builder.Length - 1, 1);
            builder.Append("}");

            return builder.ToString();
        }


        /// <summary>
        /// 将对象转换成JSON数据
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="valueTypeToString"></param>
        /// <returns></returns>
        public static string SerializeObj(object obj, bool valueTypeToString)
        {
            IList<string> properties = new List<string>();
            PropertyInfo[] propertyInfos = obj.GetType().GetProperties();
            foreach (var p in propertyInfos)
            {
                properties.Add(p.Name);
            }
            Type t = obj.GetType();

            #region 内部方法

            Func<string, bool> hasAttribute = (propertyName) =>
            {
                PropertyInfo info = t.GetProperty(propertyName);
                if (info == null)
                    return false;
                object[] attrs = info.GetCustomAttributes(typeof(NonJsonSerializeAttribute), true);
                return attrs != null && attrs.Length > 0;
            };

            Func<string, string, string> GetAttribute = (propertyName, attributeName) =>
            {
                string attrValue = string.Empty;
                PropertyInfo pi = t.GetProperty(propertyName);

                if (pi == null)
                {
                    throw new TypeLoadException("类型:" + t.ToString() + " 不存在属性" + propertyName);
                }
                attrValue = ReflectionHelper.GetAttributeValue<JsonSerializeAttribute>(pi, attributeName);
                return attrValue;
            };

            #endregion

            StringBuilder builder = new StringBuilder();

            builder.Append("{");
            foreach (var property in properties)
            {
                string key = property;
                object value = ReflectionHelper.GetPropertyValue(obj, property);
                //忽略不进行JSON序列化的属性
                if (hasAttribute(property))
                    continue;
                if (IsCusmonObj(value) && !ReflectionHelper.HasAttribute(obj, typeof(JsonSerializeAttribute), key))
                {
                    continue;
                }
                //if (hasAttribute(property))
                //{
                string ignore = GetAttribute(property, "IgnoreMobile");
                if (!string.IsNullOrEmpty(ignore) && Boolean.Parse(ignore) && WebHelper.IsMobileDevice())
                    continue;
                string cKey = GetAttribute(property, "Key");
                key = !String.IsNullOrEmpty(cKey) ? cKey : key;
                //} 

                #region 对象，list,基本类型的json化

                Type valueType = value != null ? value.GetType() : null;
                string valueOjb = "";
                if (value is IList && value != null)
                {
                    IList ilist = value as IList;
                    foreach (var m in ilist)
                    {
                        valueOjb += SerializeObj(m, valueTypeToString) + ",";
                    }
                    if (!string.IsNullOrEmpty(valueOjb))
                    {
                        valueOjb = "[" + valueOjb.Substring(0, valueOjb.Length - 1) + "]";
                        builder.Append("\"" + key + "\"");
                        builder.Append(":");
                        builder.Append(valueOjb);
                        builder.Append(",");
                    }
                }
                else if (IsCusmonObj(value) && (valueType != typeof(string)) && value != null)  // 为true，表示是.net的原生类型，即基础类型，注意string类型，自定义的struct，class不是原生类型
                {
                    valueOjb = SerializeObj(value, valueTypeToString);
                    builder.Append("\"" + key + "\"");
                    builder.Append(":");
                    builder.Append(valueOjb);
                    builder.Append(",");
                }
                else
                {
                    builder.Append("\"" + key + "\"");
                    builder.Append(":");

                    if (!valueTypeToString && (value is Int32 || value is Boolean || value is Decimal || value is Double))
                    {
                        builder.Append(value.ToString().ToLower());
                    }
                    else
                    {
                        builder.Append("\"" + FormatString(value) + "\"");
                    }
                    builder.Append(",");

                    if (value is Enum)
                    {
                        builder.Append("\"" + key + "Value\"");
                        builder.Append(":");
                        builder.Append("\"" + Convert.ToInt32(value) + "\"");
                        builder.Append(",");
                    }
                }

                #endregion

            }
            if (builder.ToString().Length > 1)
            {
                builder.Remove(builder.Length - 1, 1);
            }            
            builder.Append("}");

            return builder.ToString();
        }

        /// <summary>
        /// json化列表
        /// </summary>
        /// <param name="list"></param>
        /// <param name="valueTypeToString"></param>
        /// <returns></returns>
        public static string SerializeObjList(IList list, bool valueTypeToString)
        {
            string str = "";
            StringBuilder sb = new StringBuilder();
            foreach (var v in list)
            {
                sb.Append(SerializeObj(v, valueTypeToString) + ",");
            }
            if (!string.IsNullOrEmpty(sb.ToString()))
            {
                str = sb.ToString();
                str = "[" + str.Substring(0, str.Length - 1) + "]";
            }
            return str;
        }

        /// <summary>
        /// json格式转化成健值对
        /// </summary>
        /// <param name="jsonstr"></param>
        /// <returns></returns>
        Dictionary<string, string> JsonToArray(string jsonstr)
        {
            Dictionary<string, string> dictionary = new Dictionary<string, string>();

            #region

            Action<string, string, MatchCollection> action = (regexkey, regexvalue, machs) =>
            {
                string matchvalue = "";
                Regex regex_key = new Regex(regexkey);
                Regex regex_value = new Regex(regexvalue);
                if (machs.Count > 0)
                {
                    foreach (Match v in machs)
                    {
                        matchvalue = v.Value;
                        string key = regex_key.Match(matchvalue).Value;
                        string value = regex_value.Match(matchvalue).Value;
                        dictionary.Add(key, value);
                    }
                }
            };

            #endregion

            string regex_str_NoneSemicolon = "\"[^\"]+?\":[^\"]+?(?=[,}])";
            string regex_str_Semicolon = "\"[^\"]+?\":\"[^\"]+?\"";
            string regex_str_List = "\"[^\"]*\":\\[.*?\\]";

            Regex regex_List = new Regex(regex_str_List);
            Regex regex_NoneSemicolon = new Regex(regex_str_NoneSemicolon);
            Regex regex_Semicolon = new Regex(regex_str_Semicolon);
            MatchCollection matchs_List = regex_List.Matches(jsonstr);
            jsonstr = Regex.Replace(jsonstr, regex_str_List + ",", "");
            MatchCollection match_NoneSemicolon = regex_NoneSemicolon.Matches(jsonstr);
            MatchCollection matchs_Semicolon = regex_Semicolon.Matches(jsonstr);
            string regex_str_key = "(?<=\")[^\"]+?(?=\":)";
            string regex_str_value = "(?<=:).+";
            action(regex_str_key, regex_str_value, match_NoneSemicolon);
            regex_str_key = "(?<=\")[^\"]+?(?=\":)";
            regex_str_value = "(?<=:\").+(?=\")";
            action(regex_str_key, regex_str_value, matchs_Semicolon);

            regex_str_key = "(?<=\")[^\"]+?(?=\":)";
            regex_str_value = "(?<=:)\\[.+?\\]";
            action(regex_str_key, regex_str_value, matchs_List);
            return dictionary;
        }

        /// <summary>
        /// 判断是否是自定义obj类型
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        static bool IsCusmonObj(object obj)
        {
            if (obj != null)
            {
                Type objType = obj.GetType();
                if (objType.BaseType != typeof(Enum) && !objType.Module.Name.Contains("mscorlib") && (objType != typeof(string)))  // 为true，表示是.net的原生类型，即基础类型，注意string类型，自定义的struct，class不是原生类型
                {
                    return true;
                }
            }
            return false;
        }

        ///// <summary>
        ///// 将对象转换成JSON数据
        ///// </summary>
        ///// <param name="t"></param>
        ///// <param name="childObjNames">要json化的属性</param>
        ///// <returns></returns>
        //public static string JsonSerialize(object t, List<string> childObjNames)
        //{
        //    string jsonstr = JsonConverter.SerializeObj(t);
        //    string childStr = "";
        //    Type type = t.GetType();




        //    for (int i = 0; i < childObjNames.Count; i++)
        //    {
        //        PropertyInfo pro = type.GetProperty(childObjNames[i]);
        //        object obj = pro.GetValue(t, null);
        //        if (obj != null)
        //        {
        //            string regexstr = "\"" + childObjNames[i] + "\":\".*?\"";
        //            if (obj is System.Collections.IList)
        //            {
        //                IList list = obj as IList;
        //                foreach (var v in list)
        //                {
        //                    childStr += JsonConverter.SerializeObj(v) + ",";
        //                }
        //                if (!string.IsNullOrEmpty(childStr))
        //                {
        //                    childStr = childStr.Substring(0, childStr.Length - 1);
        //                    childStr = "[" + childStr + "]"; 
        //                }
        //            }
        //            else
        //            {
        //                childStr = JsonConverter.Serialize(obj);                         
        //            }
        //            jsonstr = System.Text.RegularExpressions.Regex.Replace(jsonstr, regexstr, "\"" + childObjNames[i] + "\":" + childStr);
        //        }
        //    }
        //    return jsonstr;
        //}

        /// <summary>
        /// 将对象集合转换成JSON数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs">需要json化的对象实例</param>
        /// <param name="properties">需要json化的属性名集合，为null时表示json化所有可json化的属性</param>
        /// <param name="valueTypeToString">值类型是否转换为字符串</param>
        /// <returns></returns>
        public static string Serialize<T>(IEnumerable<T> objs, IList<string> properties, bool valueTypeToString)
        {
            if (objs == null || objs.Count() == 0) return string.Empty;

            if (properties == null || properties.Count == 0)
                properties = ReflectionHelper.GetProperties<T>();

            StringBuilder builder = new StringBuilder("[");
            foreach (var obj in objs)
            {
                builder.Append(Serialize<T>(obj, properties, valueTypeToString));
                builder.Append(",");
            }
            if (objs.Count() > 0)
            {
                builder.Remove(builder.Length - 1, 1);
            }
            builder.Append("]");
            return builder.ToString();

        }

        /// <summary>
        /// 即将过期：将对象转换成JSON数据（所有类型均转化为字符串），请用Serialize替代
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">需要json化的对象实例,json化所有可json化的属性</param>
        /// <returns></returns>
        public static string ObjectToJson<T>(T obj)
        {
            return Serialize<T>(obj, null, true);
        }

        /// <summary>
        ///  即将过期：将对象转换成JSON数据（所有类型均转化为字符串），请用Serialize替代
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objs">需要json化的对象实例,json化所有可json化的属性</param>
        /// <returns></returns>
        public static string ObjectToJson<T>(IEnumerable<T> objs)
        {
            return Serialize<T>(objs, null, true);
        }

        /// <summary>
        /// 格式化：去掉空格，换行，制表符
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static string FormatString(object obj)
        {
            if (obj == null)
                return string.Empty;

            string s = obj.ToString();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
            {
                char c = s.ToCharArray()[i];
                switch (c)
                {
                    case '\"':
                        sb.Append("\\\""); break;
                    case '\\':
                        sb.Append("\\\\"); break;
                    case '/':
                        sb.Append("\\/"); break;
                    case '\b':
                        sb.Append("\\b"); break;
                    case '\f':
                        sb.Append("\\f"); break;
                    case '\n':
                        sb.Append("\\n"); break;
                    case '\r':
                        sb.Append("\\r"); break;
                    case '\t':
                        sb.Append("\\t"); break;
                    default:
                        sb.Append(c); break;
                }
            }
            return sb.ToString();
        }
    }
}
